package com.mf.controller.characterThread;

import com.mf.result.Result;
import io.swagger.v3.oas.annotations.Operation;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicStampedReference;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @Author: lmf
 * @Create: 2025/5/13 21:55
 * @module 原子性
 */
@RestController
@RequestMapping("/characterThread")
public class CharacterThread {
    static int count = 0;

    @Operation(summary = "使用synchronized保证原子性")
    @GetMapping("useSynchronized")
    public Result<Integer> useSynchronized() throws InterruptedException {

        final Thread t1 = new Thread(() -> {
            for (int i = 0; i < 100; i++) {
                increment();
            }
        });

        final Thread t2 = new Thread(() -> {
            for (int i = 0; i < 100; i++) {
                increment();
            }
        });
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        return Result.success(count);
    }

    private synchronized void increment() {
        count++;
    }

    private final AtomicInteger countAsc = new AtomicInteger(0);

    @Operation(summary = "使用cas保证原子性")
    @GetMapping("useCAS")
    public Result<Integer> useCAS() throws InterruptedException {
        final Thread t1 = new Thread(() -> {
            for (int i = 0; i < 100; i++) {
                countAsc.incrementAndGet();
            }
        });

        final Thread t2 = new Thread(() -> {
            for (int i = 0; i < 100; i++) {
                countAsc.incrementAndGet();
            }
        });
        t1.start();
        t2.start();
        t1.join();
        t2.join();

        return Result.success(countAsc.get());
    }

    @Operation(summary = "使用cas避免ABA问题方式")
    @GetMapping("casReference")
    public Result<String> casReference() {
        // 默认值和默认版本号
        final AtomicStampedReference<String> reference = new AtomicStampedReference<>("AAA", 1);
        // 旧值
        final String oldValue = reference.getReference();
        // 旧版本
        final int oldVersion = reference.getStamp();
        // 第一次修改版本能够对应上修改可以成功
        final boolean b = reference.compareAndSet(oldValue, "BBB", oldVersion, oldVersion + 1);
        // 第二次修改版本不能够对应上修改失败
        final boolean b1 = reference.compareAndSet(oldValue, "CCC", oldVersion, oldVersion + 1);

        return Result.success("第一次修改B" + b + "第二次修改B1" + b1);
    }

    private Integer count2 = 0;
    private final ReentrantLock lock = new ReentrantLock();

    private void increment2() {
        // 获取锁
        lock.lock();
        try {
            count2++;
        } finally {
            // 释放锁
            lock.unlock();
        }
    }

    @Operation(summary = "使用lock锁保证原子性")
    @GetMapping("lock")
    public Result<Integer> lock() {
        new Thread(() -> {
            for (int i = 0; i < 100; i++) {
                increment2();
            }
        }).start();

        new Thread(() -> {
            for (int i = 0; i < 100; i++) {
                increment2();
            }
        }).start();

        return Result.success(count2);
    }


    private final ThreadLocal<Integer> threadLoader = new ThreadLocal<>();
    private Integer count3 = 0;

    @Operation(summary = "使用ThreadLocal保证原子性")
    @GetMapping("threadLocal")
    public Result<Integer> threadLocal() {
        final Thread thread = increment3();
        final Thread thread2 = increment3();
        final Thread thread3 = increment3();
        final Thread thread4 = increment3();
        thread.start();
        thread2.start();
        thread3.start();
        thread4.start();
        try {
            thread.join();
            thread2.join();
            thread3.join();
            thread4.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


        System.out.println("总数: " + count3);

        return Result.success(count3);
    }

    private Thread increment3() {
        return new Thread(() -> {
            threadLoader.set(0);
            for (int i = 0; i < 100; i++) {
                threadLoader.set(threadLoader.get() + 1);
            }
            count3 += threadLoader.get();
            System.out.println("线程1: " + threadLoader.get());
        });
    }

}
